package Volatitle;




/**
 * @author: QianMo
 * @date: 2021/12/24 13:07
 * @mark: volatile关键字
 */
public class VolatileTest {
    /**
     * main 方法作为一个主线程
     */
//    public static void main(String[] args) {
//        MyThread myThread = new MyThread();
//        // 开启线程
//        myThread.start();
//
//        // 主线程执行
//        for (; ; ) {
//            if (myThread.isFlag()) {
//                System.out.println("主线程访问到 flag 变量");
//            }
//        }
//    }

    /**
     *     内存可见性也可以通过加锁进行实现
     *
     *     这里大家应该有个疑问是，为什么加锁后就保证了变量的内存可见性了？
     *     因为当一个线程进入 synchronizer 代码块后，线程获取到锁，会清空本地内存，
     *     然后从主内存中拷贝共享变量的最新值到本地内存作为副本，执行代码，又将修改后的副本值刷新到主内存中，
     *     最后线程释放锁。
     */
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        // 开启线程
        myThread.start();

        // 主线程执行
        for (; ; ) {
            synchronized (myThread) {
                if (myThread.isFlag()) {
                    System.out.println("主线程访问到 flag 变量");
                }
            }
        }
    }
}
/**
 * 子线程类
 */
class MyThread extends Thread {

    /**
     * 总结：
     *  不加volatile： 线程对共享变量的修改没有即时更新到主内存，或者线程没能够即时将共享变量的最新值同步到工作内存中
     *  ，从而使得线程在使用共享变量的值时，该值并不是最新的。
     *  结果：不会打印 主线程访问到 flag 变量
     *  加了之后：
     *  控制台可以一直输出
     *
     *  因此：volatile 可以保证内存可见性
     *

     *
     */
    private volatile  boolean flag = false;
//    private   boolean flag = false;

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 修改变量值
        flag = true;
        System.out.println("flag = " + flag);
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
